# constansts and utility functions
import pygame, random, sys, math
import colorsnew as colorlib

WIDTH, HEIGHT = 800, 600
DEBUG = False
NUM_BLOCKS = 10
block_dimensions = [20, 15]
NUM_BAD_BLOCKS = 1 # the number of bad blocks
speed_inc = 5
normal_speed = 3
dec_func_prob = 20 # probability of decreasing speed due to friction
max_score = 9
acceleration = 2
deceleration_rate = 10
PROB_TO_MOVE_AWAY = 50
GRAVITY_PROB = 30
#speed_mode = 1

class ColorScheme():
    def __init__(self):
        self.black = colorlib.random_color('black')
        self.white = colorlib.random_color('white')
        self.red = colorlib.random_color('red')
        self.yellow = colorlib.random_color('yellow')
        ## random color from groups

        self.new_block_color = random.choice(colorlib.color_groups)

    def new_bg_Colors(self):
        self.new_block_color = random.choice(colorlib.color_groups)

    def new_Colors(self):
        self.red = colorlib.random_color('red')
        self.yellow = colorlib.random_color('yellow')
        self.white = colorlib.random_color('white')
        self.new_block_color = random.choice(colorlib.color_groups)

def abs_speed(speed):
    return round(math.sqrt(speed[0]**2 + speed[1]**2),3)

## Bad blocks speed
## TODO: increase the speed with dx instead of just set it
def func(dist):
    if random.randrange(100) < dec_func_prob:
        if abs(dist) > 200:
            return 2*sgn(dist)
        else : return sgn(dist)
    return 0

def func2(dist):
    if abs(dist) < 75:
        return sgn(dist)
    return 0

def sgn(x):
    if x == 0: return 0
    elif (x>0): return 1
    else : return -1

# takes a speed argument x
# and decreases it wtr to its absolute value
# in the physical model
# we have F_fric = C*speed
def dec_func(x):
    # that only happens dec_func_prob % of all time
    if random.randrange(100) < dec_func_prob:
        return (-sgn(x)*(abs(x)//deceleration_rate + 1))
    else:  return 0

# variant of dec_func for food blocks
def food_dec_func(x):
    if random.randrange(100) < dec_func_prob:
        return (-sgn(x-1)*(abs(x-1)//deceleration_rate + 1))
    else: return 0

# acceleration
def inc_func(speed_mode = 2, speed = [0,0]):
    if speed_mode == 1:
        if abs_speed(speed) < 20:
            return acceleration*3
        else : return acceleration//3
    if speed_mode == 2:
        return acceleration
    if speed_mode == 3:
        if abs_speed(speed) < 20:
            return max(acceleration//3, 1)
        else : return acceleration*3


#----------- Block class. You eat or become eaten by blocks. ------------ 
# note: I removed the bad block class and merged them with block   
class Block(pygame.sprite.Sprite):
    """Bla, bla, bla, docstring."""

    def __init__(self, color, width, height, bad=False,max_x_pos = WIDTH, max_y_pos = HEIGHT):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface([width + random.randrange(-width//3, width//3), height + random.randrange(-height//3, height//3)])
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.speed = [0, 1]
        self.bad = bad
        if self.bad: self.speed = [0, 0]
        self.max_x_pos = max_x_pos
        self.max_y_pos = max_y_pos
        self.dist = [random.randrange(-2, 3), random.randrange(-2, 3)]

    def move(self, xdiff, ydiff, xpos1, ypos1,xpos2,ypos2,dead):
        dist = ((xpos1-self.rect.x)**2+(ypos1-self.rect.y)**2)<((xpos2-self.rect.x)**2+(ypos2-self.rect.y)**2)
        if (dist or dead[1]) and not dead[0]:
            xpos = xpos1
            ypos = ypos1
        else:
            xpos = xpos2
            ypos = ypos2

        if (self.rect.x > self.max_x_pos):
            self.rect.x = 0
            
        if (self.rect.x < 0):
            self.rect.x = self.max_x_pos

        if (self.rect.y > self.max_y_pos):
            self.rect.y = 0

        if (self.rect.y < 0):
            self.rect.y = self.max_y_pos    
       
        if random.randrange(100) < PROB_TO_MOVE_AWAY:
            dist = math.sqrt((xpos - self.rect.x)**2 + (ypos - self.rect.y)**2)
            if (dist < 125):
                self.speed[0] -= func2(xpos - self.rect.x)
                self.speed[1] -= func2 (ypos - self.rect.y)
            absspeed = math.sqrt((self.speed[0])**2 + self.speed[1]**2)
            if absspeed > 4:
                self.speed[0] += dec_func(self.speed[0])
                self.speed[1] += food_dec_func(self.speed[1])    
        
        if random.randrange(100) < GRAVITY_PROB and self.speed[1] < 3:
            self.speed[1] += 1
                
        self.rect.x += xdiff + self.speed[0]
        self.rect.y += ydiff + self.speed[1]

    def movebad(self,xpos1,ypos1,xpos2,ypos2,dead):
        dist = ((xpos1-self.rect.x)**2+(ypos1-self.rect.y)**2)<((xpos2-self.rect.x)**2+(ypos2-self.rect.y)**2)
        if (dist or dead[1]) and not dead[0]:
            disx = xpos1-self.rect.x
            disy = ypos1-self.rect.y
        else:
            disx = xpos2-self.rect.x
            disy = ypos2-self.rect.y

        # they tend to clut together after a while
        self.rect.x += (self.speed[0] + self.dist[0])
        self.rect.y += (self.speed[1] + self.dist[1])
        
        self.speed[0] += func(disx)
        self.speed[1] += func(disy)
        
        ## friction
        self.speed[0] += dec_func(self.speed[0])
        self.speed[1] += dec_func(self.speed[1])
        ## set a new dist
        #if random.randrange(100) > 50:
         #   self.dist = [random.randrange(-2, 3), random.randrange(-2, 3)]
